/**************************************************************************//**
 * @item     CosyOS Kernel
 * @file     os_taskmgr.c
 * @brief    CosyOS-任务管理器（Taskmgr）
 * @author   迟凯峰
 * @version  V3.3.1
 * @date     2023.07.19
 ******************************************************************************/

#include "os_link.h"

#if SYSCFG_DEBUGGING == __ENABLED__

static char str[8];
static char _DEBUG_MEM_ * _SYS_MEM_ mptr;

#define _chrcpy_(c) *mptr++ = c

static void _spccpy_(u8 n)
{
	do{
		*mptr++ = ' ';
	}while(--n);
}

static void _strcpy_(const char *sub)
{
	while(*sub)
	{
		*mptr++ = *sub++;
	}
}

static u8 _strlen_(const char *src)
{
	u8 i = 0;
	while(*src++)
	{
		i++;
	}
	return i;
}

static void _u8str_(const u8 var)
{
	char _XDATA_MEM_ *ptr = str;
	if(var >= 100)
	{
		*ptr++ = var / 100 + '0';
		goto Lable_2;
	}
	else if(var >= 10)
	{
		*ptr++ = var / 10 + '0';
		goto Lable_1;
	}
	else
	{
		*ptr++ = var + '0';
		goto Lable_0;
	}
	Lable_2: *ptr++ =(var % 100) / 10 + '0';
	Lable_1: *ptr++ =(var % 10) + '0';
	Lable_0: *ptr = '\0';
}

static void _u16str_(const u16 var)
{
	char _XDATA_MEM_ *ptr = str;
	if(var >= 10000)
	{
		*ptr++ = var / 10000 + '0';
		goto Lable_4;
	}
	else if(var >= 1000)
	{
		*ptr++ = var / 1000 + '0';
		goto Lable_3;
	}
	else if(var >= 100)
	{
		*ptr++ = var / 100 + '0';
		goto Lable_2;
	}
	else if(var >= 10)
	{
		*ptr++ = var / 10 + '0';
		goto Lable_1;
	}
	else
	{
		*ptr++ = var + '0';
		goto Lable_0;
	}
	Lable_4: *ptr++ =(var % 10000) / 1000 + '0';
	Lable_3: *ptr++ =(var % 1000) / 100 + '0';
	Lable_2: *ptr++ =(var % 100) / 10 + '0';
	Lable_1: *ptr++ =(var % 10) + '0';
	Lable_0: *ptr = '\0';
}

static u8 _u16len_(const u16 var)
{
	if(var >= 10000) return 5;
	else if(var >= 1000) return 4;
	else if(var >= 100) return 3;
	else if(var >= 10) return 2;
	else return 1;
}

static void _used_ratio_(const u16 permill)
{
	u8 i;
	if(!permill)
	{
		str[0] = '0';
		str[1] = '\0';
		i = 2;
	}
	else
	{
		_u16str_(permill);
		i = _strlen_(str);
		if(i > 2)
		{
			str[i]   = str[i-1];
			str[i-1] = str[i-2];
			str[i-2] = '.';
			str[i+1] = '\0';
			i += 2;
		}
		else
		{
			if(i == 1)
			{
				str[2] = '0';
				str[3] = str[0];
			}
			else
			{
				str[2] = str[0];
				str[3] = str[1];
			}
			str[0] = '0';
			str[1] = '.';
			str[4] = '\0';
			i = 5;
		}
	}
	_spccpy_((u8)(__CPULEN__ - i));
	_strcpy_(str);
	_chrcpy_('%');
}

#if SYSCFG_TASKPCMONITOR == __ENABLED__
static void _u8str16_(const u8 var)
{
	str[0] = (var >> 4) + '0';
	str[1] = (var & 0x0F) + '0';
	if(str[0] > '9') str[0] += 0x07;
	if(str[1] > '9') str[1] += 0x07;
	*mptr++ = str[0];
	*mptr++ = str[1];
}
#endif

uCreateTask_TimQry(__TMID_TASKMGR__, vTaskmgrBinary, true, Taskmgr, SYSCFG_TASKPRIORITY - 1, __STACKSIZE_TASKMGR__, 0, 0)
{
	static char _DEBUG_MEM_ *p[2];
	mptr = vTaskmgrSendBuff;
	// Title1
	_strcpy_("CosyOS Taskmgr");
	_spccpy_(SYSCFG_TASKNAMEMAXLEN + __TIDLEN__ + __TPLLEN__ + __STALEN__ - 14);
	p[0] = mptr;
	_spccpy_(__CPULEN__ + __RAMLEN__);
	_strcpy_("\r\n");
	// Title2
	_strcpy_("Name");
	_spccpy_(SYSCFG_TASKNAMEMAXLEN - 4);
	_spccpy_(__TIDLEN__ - 3);
	_strcpy_("TID");
	_spccpy_(__TPLLEN__ - 3);
	_strcpy_("TPL");
	_spccpy_(__STALEN__ - 3);
	_strcpy_("STA");
	_spccpy_(__CPULEN__ - 3);
	_strcpy_("CPU");
	_spccpy_(__RAMLEN__ - 3);
	_strcpy_("RAM\r\n");
	// NULL Line
	_strcpy_("\r\n");
	p[1] = mptr;
	while(true)
	{
		static tTimQry upspeed = (1000UL * SYSCFG_TASKMGRUPSPEED) / SYSCFG_STKCYCLE;
		tsTaskNode     node_temp;
		tspTaskNode    node_curr = sTaskNode(&vTaskHandle_Taskmgr);
		u16            permill1 = 10000;
		#if SYSCFG_TASKPCMONITOR == __ENABLED__
		tPC            pc = vPC;
		#endif
		mptr = p[1];
		while(true)
		{
			u16 permill2;
			mEnterCritical;
			node_temp = *node_curr;
			node_curr->usedtime[0] = node_curr->usedtime[1] = 0;
			mExitCritical;
			// Name
			_strcpy_(node_temp.NAME);
			if(SYSCFG_TASKNAMEMAXLEN > _strlen_(node_temp.NAME))
			{
				_spccpy_((u8)(SYSCFG_TASKNAMEMAXLEN - _strlen_(node_temp.NAME)));
			}
			// TID
			_u8str_	(node_temp.TID);
			_spccpy_((u8)(__TIDLEN__ - _strlen_(str)));
			_strcpy_(str);
			// TPL
			_u8str_	(node_temp.TPL);
			_spccpy_((u8)(__TPLLEN__ - _strlen_(str)));
			_strcpy_(str);
			// STA
			_spccpy_(__STALEN__ - 3);
			if(node_temp.state <= __FLOATING__)
			{
				_strcpy_("RDY");
			}
			else if(node_temp.state == __BLOCKED__)
			{
				node_temp.blocktype &= 0xF0;
				     if(node_temp.blocktype == __DELAY__)       _strcpy_("DLY");
				else if(node_temp.blocktype == __BINARY__)      _strcpy_("BIN");
				else if(node_temp.blocktype == __MUTEX__)       _strcpy_("MUT");
				else if(node_temp.blocktype == __SEMAPHORE__)   _strcpy_("SEM");
				else if(node_temp.blocktype == __FLAGGROUP__)   _strcpy_("GRP");
				else if(node_temp.blocktype == __RECV_FETION__) _strcpy_("FET");
				else if(node_temp.blocktype == __RECV_DM__)     _strcpy_(" DM");
				else if(node_temp.blocktype == __RECV_MAIL__)   _strcpy_("MAL");
				else if(node_temp.blocktype == __RECV_MSG__)    _strcpy_("MSG");
			}
			else if(node_temp.state == __OVERTIME__)
			{
				_strcpy_("OSR");
			}
			else if(node_temp.state & __SUSPENDED__)
			{
				_strcpy_("SPD");
			}
			else
			{
				switch(node_temp.state)
				{
					case __STOPPED_TSOF__: _strcpy_("!OF"); break;
					case __STOPPED_TSRF__: _strcpy_("!RF"); break;
					default:               _strcpy_("XXX"); break;
				}
			}
			// CPU
			permill2 = (node_temp.usedtime[0] * 10000UL + (node_temp.usedtime[1] * 10000UL) / mSysTick_Cycle) / upspeed;
			_used_ratio_(permill2);
			if(!node_temp.TPL)
			{
				permill1 -= permill2;
			}
			// RAM
			_spccpy_((u8)(__RAMLEN__ - 4 - _u16len_((u16)node_temp.stacklen_max) - _u16len_((u16)node_temp.stacksize)));
			_u16str_(node_temp.stacklen_max);
			_strcpy_(str);
			_strcpy_("B/");
			#if SYSCFG_TASKCREATEMODE == __STATIC__
			_chrcpy_('s');
			#else
			if(node_temp.realloc)
			{
				_chrcpy_('r');
			}
			else
			{
				_chrcpy_('m');
			}
			#endif
			_u16str_(node_temp.stacksize);
			_strcpy_(str);
			_chrcpy_('B');
			//
			_strcpy_("\r\n");
			//
			if(node_temp.next == sTaskNode(&vTaskHandle_Taskmgr))
			{
				break;
			}
			else
			{
				node_curr = node_temp.next;
			}
		}
		// CPU-TOTAL
		{
			char _DEBUG_MEM_ *p0 = mptr;
			mptr = p[0];
			_used_ratio_(permill1);
			mptr = p0;
		}
		// NULL Line
		_strcpy_("\r\n");
		// Service Stack
		#if MCUCFG_MCUARC == __ARM__
		#if MCUCFG_SVSTACKMONITOR == __ENABLED__
		if(vISS_DepthMAX > MCUCFG_ISSDEPTH) vFault.overflow_iss = true;
		_strcpy_("ISS: ");
		_u16str_(vISS_DepthMAX);
		_strcpy_(str);
		_strcpy_("/");
		_u16str_(MCUCFG_ISSDEPTH);
		_strcpy_(str);
		_strcpy_(".\r\n");
		#endif
		#endif
		// Task PC
		#if SYSCFG_TASKPCMONITOR == __ENABLED__
		{
			_strcpy_("Task-PC: ");
			#if MCUCFG_PCLEN > 2
			_u8str16_((u8)(pc >> 24));
			_u8str16_((u8)(pc >> 16));
			#endif
			_u8str16_((u8)(pc >> 8));
			_u8str16_((u8)(pc));
			_strcpy_(".\r\n");
		}
		#endif
		// SysTick_Handler
		#if SYSCFG_STKTIMECOUNT == __ENABLED__
		mEnterCritical;
		if(vSTK_Counter2)
		{
			u32 counter1 = vSTK_Counter1;
			u32 counter2 = vSTK_Counter2;
			vSTK_Counter1 = vSTK_Counter2 = 0;
			mExitCritical;
			mTaskmgr_Counting;
			_strcpy_("SysTick: ");
			_u16str_((u16)(counter2 / 100));
			_strcpy_(str);
			_chrcpy_('.');
			_u8str_((u8)((counter2 % 100) / 10));
			_strcpy_(str);
			_u8str_((u8)(counter2 % 10));
			_strcpy_(str);
			_strcpy_("us.\r\n");
		}
		else
		{
			mExitCritical;
		}
		#endif
		// Alarm
		if(*(u8 *)&vAlarm)
		{
			_strcpy_("Alarm: ");
			if(vAlarm.overflow_taskqueue)    _strcpy_("otq, ");
			if(vAlarm.overflow_taskpriority) _strcpy_("otp, ");
			if(vAlarm.overflow_msgqueue)     _strcpy_("omq, ");
			if(vAlarm.overtime_saferuntime)  _strcpy_("osr, ");
			mptr -= 2;
			_strcpy_(".\r\n");
		}
		// Fault
		if(*(u8 *)&vFault)
		{
			_strcpy_("Fault: ");
			if(vFault.mallocfail_msgnode)    _strcpy_("mmn, ");
			if(vFault.mallocfail_tasknode)   _strcpy_("mtn, ");
			if(vFault.mallocfail_taskstack)  _strcpy_("mts, ");
			if(vFault.reallocfail_taskstack) _strcpy_("rts, ");
			if(vFault.overflow_taskstack)    _strcpy_("ots, ");
			if(vFault.fail_startuptask)      _strcpy_("fst, ");
			if(vFault.error_recvmsg)         _strcpy_("erm, ");
			#if MCUCFG_MCUARC == __ARM__
			#if MCUCFG_SVSTACKMONITOR == __ENABLED__
			if(vFault.overflow_iss)          _strcpy_("ois, ");
			#endif
			#endif
			mptr -= 2;
			_strcpy_(".\r\n");
		}
		// NULL Line
		_strcpy_("\r\n");
		// string tail
		_chrcpy_('\0');
		//
		mEnterCritical;
		upspeed = vTIMQRY_BUFF[__TMID_TASKMGR__];
		vDebugSendFlag |= TaskmgrSendFlag;
		__suspend_task(vTASKING);
	}
	uEndTasking;
}

#endif
